using System;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using StackExchange.Redis;

namespace MatrixFramework.Shared.Application.Caching
{
    /// <summary>
    /// 分布式缓存配置
    /// </summary>
    public static class DistributedCacheConfiguration
    {
        /// <summary>
        /// 添加分布式缓存支持
        /// </summary>
        public static IServiceCollection AddDistributedCacheSupport(this IServiceCollection services, Action<DistributedCacheOptions>? configureOptions = null)
        {
            // 添加基础缓存服务
            services.AddStackExchangeRedisCache(options =>
            {
                // 默认配置，可以通过configureOptions覆盖
                options.Configuration = "localhost:6379";
                options.InstanceName = "MatrixFramework";
            });

            // 配置缓存选项
            if (configureOptions != null)
            {
                services.Configure(configureOptions);
            }
            else
            {
                // 使用默认配置
                services.Configure<DistributedCacheOptions>(options =>
                {
                    options.DefaultExpiration = TimeSpan.FromMinutes(30);
                    options.KeyPrefix = "MatrixFramework";
                    options.EnableLogging = true;
                    options.EnableMetrics = true;
                });
            }

            // 注册自定义缓存服务
            services.AddTransient<DistributedCacheManager>();
            services.AddTransient<CacheKeyManager>();

            // 注册缓存拦截器
            services.AddTransient(typeof(CacheInterceptor));

            return services;
        }

        /// <summary>
        /// 添加内存缓存支持（作为降级方案）
        /// </summary>
        public static IServiceCollection AddMemoryCacheSupport(this IServiceCollection services)
        {
            services.AddMemoryCache();
            return services;
        }

        /// <summary>
        /// 添加多层缓存支持
        /// </summary>
        public static IServiceCollection AddMultiLayerCacheSupport(this IServiceCollection services, Action<MultiLayerCacheOptions>? configureOptions = null)
        {
            // 添加内存缓存作为L1缓存
            services.AddMemoryCache();

            // 添加分布式缓存作为L2缓存
            services.AddDistributedCacheSupport();

            // 配置多层缓存选项
            if (configureOptions != null)
            {
                services.Configure(configureOptions);
            }
            else
            {
                services.Configure<MultiLayerCacheOptions>(options =>
                {
                    options.EnableL1Cache = true;
                    options.L1CacheExpiration = TimeSpan.FromMinutes(5);
                    options.L2CacheExpiration = TimeSpan.FromMinutes(30);
                    options.EnableCompression = true;
                    options.EnableEncryption = false;
                });
            }

            // 注册多层缓存管理器
            services.AddTransient<IMultiLayerCacheManager, MultiLayerCacheManager>();

            return services;
        }

        /// <summary>
        /// 添加缓存健康检查
        /// </summary>
        public static IServiceCollection AddCacheHealthChecks(this IServiceCollection services)
        {
            services.AddHealthChecks()
                .AddCheck<RedisHealthCheck>("redis")
                .AddCheck<CacheHealthCheck>("cache");

            return services;
        }
    }

    /// <summary>
    /// 分布式缓存选项
    /// </summary>
    public class DistributedCacheOptions
    {
        /// <summary>
        /// 默认过期时间
        /// </summary>
        public TimeSpan DefaultExpiration { get; set; } = TimeSpan.FromMinutes(30);

        /// <summary>
        /// 缓存键前缀
        /// </summary>
        public string KeyPrefix { get; set; } = "MatrixFramework";

        /// <summary>
        /// 是否启用日志记录
        /// </summary>
        public bool EnableLogging { get; set; } = true;

        /// <summary>
        /// 是否启用指标收集
        /// </summary>
        public bool EnableMetrics { get; set; } = true;

        /// <summary>
        /// Redis连接字符串
        /// </summary>
        public string RedisConnectionString { get; set; } = "localhost:6379";

        /// <summary>
        /// Redis实例名称
        /// </summary>
        public string RedisInstanceName { get; set; } = "MatrixFramework";

        /// <summary>
        /// 连接重试次数
        /// </summary>
        public int ConnectRetry { get; set; } = 3;

        /// <summary>
        /// 连接超时时间
        /// </summary>
        public TimeSpan ConnectTimeout { get; set; } = TimeSpan.FromSeconds(10);

        /// <summary>
        /// 是否启用压缩
        /// </summary>
        public bool EnableCompression { get; set; } = false;

        /// <summary>
        /// 压缩阈值（字节）
        /// </summary>
        public int CompressionThreshold { get; set; } = 1024;

        /// <summary>
        /// 最大重试次数
        /// </summary>
        public int MaxRetries { get; set; } = 3;

        /// <summary>
        /// 重试延迟
        /// </summary>
        public TimeSpan RetryDelay { get; set; } = TimeSpan.FromMilliseconds(100);
    }

    /// <summary>
    /// 多层缓存选项
    /// </summary>
    public class MultiLayerCacheOptions
    {
        /// <summary>
        /// 是否启用L1缓存（内存缓存）
        /// </summary>
        public bool EnableL1Cache { get; set; } = true;

        /// <summary>
        /// L1缓存过期时间
        /// </summary>
        public TimeSpan L1CacheExpiration { get; set; } = TimeSpan.FromMinutes(5);

        /// <summary>
        /// L2缓存过期时间
        /// </summary>
        public TimeSpan L2CacheExpiration { get; set; } = TimeSpan.FromMinutes(30);

        /// <summary>
        /// 是否启用压缩
        /// </summary>
        public bool EnableCompression { get; set; } = true;

        /// <summary>
        /// 是否启用加密
        /// </summary>
        public bool EnableEncryption { get; set; } = false;

        /// <summary>
        /// 同步策略
        /// </summary>
        public CacheSyncStrategy SyncStrategy { get; set; } = CacheSyncStrategy.WriteThrough;

        /// <summary>
        /// 失败策略
        /// </summary>
        public CacheFailureStrategy FailureStrategy { get; set; } = CacheFailureStrategy.FailOver;
    }

    /// <summary>
    /// 缓存同步策略
    /// </summary>
    public enum CacheSyncStrategy
    {
        /// <summary>
        /// 写入时同时更新L1和L2缓存
        /// </summary>
        WriteThrough,

        /// <summary>
        /// 写入时只更新L1缓存，异步更新L2缓存
        /// </summary>
        WriteBehind,

        /// <summary>
        /// 写入时只更新L2缓存，按需加载到L1缓存
        /// </summary>
        WriteAround
    }

    /// <summary>
    /// 缓存失败策略
    /// </summary>
    public enum CacheFailureStrategy
    {
        /// <summary>
        /// 缓存失败时降级到下一层
        /// </summary>
        FailOver,

        /// <summary>
        /// 缓存失败时直接返回错误
        /// </summary>
        FailFast,

        /// <summary>
        /// 缓存失败时返回默认值
        /// </summary>
        FailSafe
    }

    /// <summary>
    /// 多层缓存管理器接口
    /// </summary>
    public interface IMultiLayerCacheManager
    {
        Task<T?> GetAsync<T>(string key, Func<Task<T?>>? factory = null) where T : class;
        Task SetAsync<T>(string key, T value, TimeSpan? expiration = null) where T : class;
        Task RemoveAsync(string key);
        Task ClearAllAsync();
    }

    /// <summary>
    /// 多层缓存管理器实现
    /// </summary>
    public class MultiLayerCacheManager : IMultiLayerCacheManager, ITransientDependency
    {
        private readonly IMemoryCache _memoryCache;
        private readonly IDistributedCache _distributedCache;
        private readonly IOptions<MultiLayerCacheOptions> _options;
        private readonly ILogger<MultiLayerCacheManager> _logger;

        public MultiLayerCacheManager(
            IMemoryCache memoryCache,
            IDistributedCache distributedCache,
            IOptions<MultiLayerCacheOptions> options,
            ILogger<MultiLayerCacheManager> logger)
        {
            _memoryCache = memoryCache;
            _distributedCache = distributedCache;
            _options = options;
            _logger = logger;
        }

        public async Task<T?> GetAsync<T>(string key, Func<Task<T?>>? factory = null) where T : class
        {
            if (_options.Value.EnableL1Cache)
            {
                // 先从L1缓存获取
                if (_memoryCache.TryGetValue(key, out T? l1Value))
                {
                    _logger.LogDebug("L1缓存命中: {Key}", key);
                    return l1Value;
                }
            }

            // 从L2缓存获取
            var l2Value = await GetFromL2CacheAsync<T>(key);
            if (l2Value != null)
            {
                // 将数据存入L1缓存
                if (_options.Value.EnableL1Cache)
                {
                    _memoryCache.Set(key, l2Value, _options.Value.L1CacheExpiration);
                }
                _logger.LogDebug("L2缓存命中: {Key}", key);
                return l2Value;
            }

            // 缓存未命中，使用工厂方法获取数据
            if (factory != null)
            {
                var data = await factory();
                if (data != null)
                {
                    await SetAsync(key, data);
                }
                return data;
            }

            return null;
        }

        public async Task SetAsync<T>(string key, T value, TimeSpan? expiration = null) where T : class
        {
            if (value == null) return;

            var l1Expiration = expiration ?? _options.Value.L1CacheExpiration;
            var l2Expiration = expiration ?? _options.Value.L2CacheExpiration;

            // 根据同步策略处理缓存更新
            switch (_options.Value.SyncStrategy)
            {
                case CacheSyncStrategy.WriteThrough:
                    // 同时更新L1和L2缓存
                    if (_options.Value.EnableL1Cache)
                    {
                        _memoryCache.Set(key, value, l1Expiration);
                    }
                    await SetToL2CacheAsync(key, value, l2Expiration);
                    break;

                case CacheSyncStrategy.WriteBehind:
                    // 更新L1缓存，异步更新L2缓存
                    if (_options.Value.EnableL1Cache)
                    {
                        _memoryCache.Set(key, value, l1Expiration);
                    }
                    _ = Task.Run(async () => await SetToL2CacheAsync(key, value, l2Expiration));
                    break;

                case CacheSyncStrategy.WriteAround:
                    // 只更新L2缓存
                    await SetToL2CacheAsync(key, value, l2Expiration);
                    break;
            }

            _logger.LogDebug("缓存设置完成: {Key}, 策略: {Strategy}", key, _options.Value.SyncStrategy);
        }

        public async Task RemoveAsync(string key)
        {
            if (_options.Value.EnableL1Cache)
            {
                _memoryCache.Remove(key);
            }
            await _distributedCache.RemoveAsync(key);
            _logger.LogDebug("缓存删除: {Key}", key);
        }

        public async Task ClearAllAsync()
        {
            if (_options.Value.EnableL1Cache)
            {
                // 清空内存缓存
                (_memoryCache as MemoryCache)?.Compact(1.0);
            }

            // 清空分布式缓存需要根据具体实现处理
            _logger.LogInformation("缓存清空完成");
        }

        private async Task<T?> GetFromL2CacheAsync<T>(string key) where T : class
        {
            try
            {
                var cachedData = await _distributedCache.GetStringAsync(key);
                if (string.IsNullOrEmpty(cachedData)) return null;

                return System.Text.Json.JsonSerializer.Deserialize<T>(cachedData);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "从L2缓存获取数据失败: {Key}", key);
                return null;
            }
        }

        private async Task SetToL2CacheAsync<T>(string key, T value, TimeSpan expiration) where T : class
        {
            try
            {
                var options = new DistributedCacheEntryOptions
                {
                    AbsoluteExpirationRelativeToNow = expiration
                };

                var serializedData = System.Text.Json.JsonSerializer.Serialize(value);
                await _distributedCache.SetStringAsync(key, serializedData, options);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "设置L2缓存失败: {Key}", key);
            }
        }
    }

    /// <summary>
    /// Redis健康检查
    /// </summary>
    public class RedisHealthCheck : Microsoft.Extensions.Diagnostics.HealthChecks.IHealthCheck
    {
        private readonly IConnectionMultiplexer _redis;
        private readonly ILogger<RedisHealthCheck> _logger;

        public RedisHealthCheck(IConnectionMultiplexer redis, ILogger<RedisHealthCheck> logger)
        {
            _redis = redis;
            _logger = logger;
        }

        public async Task<Microsoft.Extensions.Diagnostics.HealthChecks.HealthCheckResult> CheckHealthAsync(
            Microsoft.Extensions.Diagnostics.HealthChecks.HealthCheckContext context,
            CancellationToken cancellationToken = default)
        {
            try
            {
                if (!_redis.IsConnected)
                {
                    return Microsoft.Extensions.Diagnostics.HealthChecks.HealthCheckResult.Unhealthy("Redis未连接");
                }

                var database = _redis.GetDatabase();
                await database.PingAsync();

                return Microsoft.Extensions.Diagnostics.HealthChecks.HealthCheckResult.Healthy("Redis连接正常");
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Redis健康检查失败");
                return Microsoft.Extensions.Diagnostics.HealthChecks.HealthCheckResult.Unhealthy($"Redis健康检查失败: {ex.Message}");
            }
        }
    }

    /// <summary>
    /// 缓存健康检查
    /// </summary>
    public class CacheHealthCheck : Microsoft.Extensions.Diagnostics.HealthChecks.IHealthCheck
    {
        private readonly IDistributedCache _cache;
        private readonly ILogger<CacheHealthCheck> _logger;

        public CacheHealthCheck(IDistributedCache cache, ILogger<CacheHealthCheck> logger)
        {
            _cache = cache;
            _logger = logger;
        }

        public async Task<Microsoft.Extensions.Diagnostics.HealthChecks.HealthCheckResult> CheckHealthAsync(
            Microsoft.Extensions.Diagnostics.HealthChecks.HealthCheckContext context,
            CancellationToken cancellationToken = default)
        {
            try
            {
                var testKey = $"health:check:{Guid.NewGuid():N}";
                var testValue = DateTime.UtcNow.ToString("O");

                await _cache.SetStringAsync(testKey, testValue, new DistributedCacheEntryOptions
          {
              AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(1)
          });
                var retrievedValue = await _cache.GetStringAsync(testKey);
                await _cache.RemoveAsync(testKey);

                if (retrievedValue == testValue)
                {
                    return Microsoft.Extensions.Diagnostics.HealthChecks.HealthCheckResult.Healthy("缓存读写正常");
                }

                return Microsoft.Extensions.Diagnostics.HealthChecks.HealthCheckResult.Degraded("缓存读写异常");
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "缓存健康检查失败");
                return Microsoft.Extensions.Diagnostics.HealthChecks.HealthCheckResult.Unhealthy($"缓存健康检查失败: {ex.Message}");
            }
        }
    }
}